using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Utility;

namespace UniAspect.Aspect
{
    /// <summary>
    /// Nice configurer for aspects that apprehends fluent interface
    /// </summary>
    public class AspectConfigurer
    {
        private readonly AspectInsertionExtension _aspectExtension;
        private readonly Type _type;
        private readonly string _name;

        public AspectConfigurer(AspectInsertionExtension aspectExtension, Type type, string name)
        {
            Guard.ArgumentNotNull(aspectExtension, "aspectExtension");
            Guard.ArgumentNotNull(type, "type");

            _aspectExtension = aspectExtension;
            _type = type;
            _name = name;
        }

        public AspectConfigurer Add<T>()
            where T : IAspect
        {
            return Add(typeof(T), null);
        }

        public AspectConfigurer Add<T>(string name)
            where T : IAspect
        {
            return Add(typeof(T), name);
        }

        public AspectConfigurer Add(Type aspectType)
        {
            return Add(aspectType, null);
        }

        /// <summary>
        /// Add aspect which will be resolved when needed
        /// </summary>
        /// <param name="aspectType"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public AspectConfigurer Add(Type aspectType, string name)
        {
            Guard.TypeIsAssignable(typeof(IAspect), aspectType, "aspectType");

            _aspectExtension.Aspects(_type, _name)
                    .Add(new UnresolvedAspect(_aspectExtension.Container, aspectType, name));
            return this;
        }

        /// <summary>
        /// Add specified created aspect
        /// </summary>
        /// <param name="aspect"></param>
        /// <returns></returns>
        public AspectConfigurer Add(IAspect aspect)
        {
            _aspectExtension.Aspects(_type, _name).Add(aspect);
            return this;
        }

        public AspectConfigurer Clear()
        {
            _aspectExtension.Aspects(_type, _name).Clear();
            return this;            
        }

        public IAspectInsertionExtension Extension
        {
            get { return _aspectExtension; }
        }

        public IUnityContainer Container
        {
            get { return _aspectExtension.Container; }
        }
    }
}